/*
Copyright (c) 2011 Guave Studios GmbH

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
macroScript AnimationReTimer category:"Animation Tools" (
	retimeobjs = #()
	
	fn getanimatedcontrollers obj = (
		local animatedcontrollers = #()
		
		if obj.numsubs > 0 then (
			for i = 1 to obj.numsubs do (
				local x = getanimatedcontrollers obj[i]
				join animatedcontrollers x
			)
		)
		else if (custAttributes.count obj) > 0 then (
			for i = 1 to obj.custattributes.count do (
				local x = getanimatedcontrollers obj.custattributes[i]
				join animatedcontrollers x
			)
		)
		else (
			if obj.controller != undefined AND obj.isAnimated then append animatedcontrollers obj.controller
		)
		return animatedcontrollers
	)

	fn getobjectanirange obj = (
		local animatedcontrollers = getanimatedcontrollers obj
		local anikeys = #()
		if animatedcontrollers.count > 0 then (
			for j in animatedcontrollers do for k in j.keys do append anikeys k.time
			return #((amin anikeys),(amax anikeys))
		)
		else return #(0,0)
	)

	fn gettimedistancearray obj timerobj acc dmt = (
		local timedistarray = #(#(),#())
		local timerobjanirange = getobjectanirange timerobj
		local objanirange = getobjectanirange obj
		for j = timerobjanirange[1] to timerobjanirange[2] by (1f*acc) do (
			append timedistarray[1] j
			append timedistarray[2] (distance (at time j timerobj.pos) (at time (objanirange[1]+((objanirange[2]-objanirange[1])*dmt)) obj.pos))
		)
		return timedistarray
	)
	
	rollout aboutart "About" (
		label label1 "AnimationReTimer" align:#center
		label label2 "(c) by Guave Studios GmbH" align:#center
	)
	
	rollout timerobjects "Timer Objects" (
		label label2 "Objects:" across:3
		button button_addobj "Add"
		button button_remobj "Remove"
		MultiListBox list_retimeobjs
		
		on button_addobj pressed do (
			objsel = (selectByName title:"Select Objects" showHidden:true single:false)
			local retimeobjsnames = #()
			if objsel != undefined do for i in objsel do  (
				if (finditem retimeobjs i) == 0 do when i deleted id:#rto obj do (
					try deleteitem retimeobjs (finditem retimeobjs obj) catch ()
					local retimeobjsnames = #()
					for j in retimeobjs do append retimeobjsnames j.name
					list_retimeobjs.items = retimeobjsnames
				)
				appendIfUnique retimeobjs i
			)
			for i in retimeobjs do append retimeobjsnames i.name
			list_retimeobjs.items = retimeobjsnames
		)
		
		on button_remobj pressed do (
			local retimeobjsnames = #()
			sel = list_retimeobjs.selection as array
			for i = sel.count to 1 by -1 do (
				deleteItem retimeobjs sel[i as integer]
			)
			for i in retimeobjs do append retimeobjsnames i.name
			list_retimeobjs.items = retimeobjsnames
		)
	)
	
	rollout referenceing "Referenceing" (
		label label3 "Animation Reference" align:#center
		slider anirefpoint type:#float range:[0.0,1.0,0.0]
		label label4 "Distance Reference" align:#center
		slider distmeasuretime type:#float range:[0.0,1.0,0.0]
	)
	
	rollout falloffsettings "Falloff Settings" (
		group "Falloff" (
			spinner falloffstart "Start:" type:#float across:2
			spinner falloffend "End:" type:#float
		)
		spinner falloffmaxdelay "Max. Delay:" type:#float
	)
	
	rollout timeing "Timeing" (
		spinner animationdelay "Delay:" type:#integer range:[-1000000000,1000000000,0]
		spinner accuracy "Accuracy:" type:#float range:[0.5,10,1]
		spinner randfact "Variation:" type:#float range:[0,1000000000,0]
		spinner seedfact "Seed:" type:#integer range:[0,1000000000,0]
		spinner lazyfactor "Lazy Animation:" type:#float
	)
	
	rollout artaction "ReTime!" (
		checkbox anidependency "Distance Dependent" checked:false
		button retime_button "RETIME!"
		progressbar progressb
		on retime_button pressed do (
		undo "ReTime" on (
			seed timeing.seedfact.value
			-- CORRECT SELECTION --
			local cursel = getCurrentSelection()
			local remobjs = #()
			for i in retimeobjs do if finditem cursel i != 0 do append remobjs (finditem cursel i)
			sort remobjs
			for i = remobjs.count to 1 by -1 do deleteitem cursel remobjs[i]
			
			case of (
				(retimeobjs.count == 0): messageBox "No timer-object(s) selected!"
				(cursel.count == 0): messageBox "No objects to be retimed selected!"
				default: (
					progressb.value = 0.0
					progressb.color = blue
					local counter = 0
					
					for i in cursel do (
						counter += 1
						local curobjAC = getanimatedcontrollers i
						if curobjAC.count > 0 then (
							local rto_timedist = #()
							local anitimes = #()
							local aniframe = 0
							for j in retimeobjs do (
								local retimeobjAC = getanimatedcontrollers j
								if retimeobjAC.count > 0 then (
									append rto_timedist (gettimedistancearray i j timeing.accuracy.value referenceing.distmeasuretime.value)
								)
							)
							
							if rto_timedist.count > 0 then (
								if anidependency.state == true then (
									local adjtimedist = #()
									for j in rto_timedist do (
										append adjtimedist (amin j[2])
									)
									aniframe = (rto_timedist[finditem adjtimedist (amin adjtimedist)][1][finditem rto_timedist[finditem adjtimedist (amin adjtimedist)][2] (amin rto_timedist[finditem adjtimedist (amin adjtimedist)][2])] + ((amin rto_timedist[finditem adjtimedist (amin adjtimedist)][2])*timeing.lazyfactor.value))
								)
								else (
									for j in rto_timedist do (
										local adjtimedist = #()
										for k=1 to j[1].count do (
											append adjtimedist (j[1][k] + (j[2][k]*timeing.lazyfactor.value))
										)
										append anitimes (amin adjtimedist)
									)
									aniframe = (amin anitimes)
								)
								
								local objanirange = getobjectanirange i
								objrandfact = (random (-timeing.randfact.value/2.0) (timeing.randfact.value/2.0))
								for j in curobjAC do (
									moveKeys j ((aniframe-(objanirange[1]+(objanirange[2]-objanirange[1])*referenceing.anirefpoint.value))+timeing.animationdelay.value+objrandfact)
								)
								progressb.value = (counter*(100.0/(cursel.count-1)))
								if progressb.value > 99 do progressb.color = green
							)
						)
					)
				)
			)
		)
		)
		on aniretime close do (
			deleteAllChangeHandlers id:#rto
		)
	)
	
	art = newRolloutFloater "AnimationReTimer" 200 480
	addRollout aboutart art rolledUp:true
	addRollout timerobjects art rolledUp:false
	addRollout referenceing art rolledUp:true
	--addRollout falloffsettings art rolledUp:true
	addRollout timeing art rolledUp:false
	addRollout artaction art rolledUp:false
)